/*
 * Dictionary.cpp
 *
 *  Created on: 26/05/2010
 *      Author: prodrig
 */

#include "HashedDictionary.h"
#include "Pair.h"
#include "DictionaryIterator.h"
#include "HashedKey.h"
#include "List.h"
#include "IKey.h"
#include "ICollectible.h"
#include "ICollection.h"
#include <stdio.h>
#include <string>
#include <sstream>

using std::string;
using std::stringstream;

#define BUCKET_SIZE 100

HashedDictionary::HashedDictionary() {
	buckets = new ICollectible *[BUCKET_SIZE];
	keys = new List();
	bckSize = BUCKET_SIZE;
	initBuckets();
}

void HashedDictionary::initBuckets() {
	for (int i = 0; i < bckSize; i++)
		buckets[i] = 0;
}

HashedDictionary::HashedDictionary(int bucketSize) {
	buckets = new ICollectible *[bucketSize];
	keys = new List();
	bckSize = bucketSize;
	initBuckets();
}

int HashedDictionary::hash(HashedKey *hashedKey) {
	return hashedKey->getHash() % bckSize;
}

ICollectible * HashedDictionary::remove(IKey *iKey) {
	int idx = hash((HashedKey*) iKey);
	Pair *p = 0, *aux = 0;
	ICollectible *ret = 0;

	if (buckets[idx] != 0) {
		bool find = 0;
		IIterator *it =
				(dynamic_cast<ICollection*> (buckets[idx]))->getIterator();
		while (it->hasCurrent() && !find) {
			p = (Pair*) it->current();
			it->next();
			if (p->getKey()->equals(iKey)) {
				aux = p;
				find = 1;
			}
		}
		delete it;
		if (aux != 0) {
			ret = aux->getValue();
			(dynamic_cast<ICollection*> (buckets[idx]))->remove(aux);
			delete aux;
			keys->remove(iKey);
		}
	}
	return ret;
}

void HashedDictionary::add(IKey *iKey, ICollectible *iCollectible) {
	int idx = hash((HashedKey*) iKey);
	Pair *p;
	if (buckets[idx] == 0) {
		ICollection *col = new List();
		p = new Pair(iKey, iCollectible);
		col->add(p);
		buckets[idx] = col;
		if (!keys->member(iKey))
			keys->add(iKey);
	} else {
		bool find = 0;
		IIterator *it =
				(dynamic_cast<ICollection*> (buckets[idx]))->getIterator();
		while (it->hasCurrent() && !find) {
			p = (Pair*) it->current();
			it->next();
			if (p->getKey()->equals(iKey)) {
				p->setValue(iCollectible);
				find = 1;
			}
		}
		delete it;
		if (!find) {
			p = new Pair(iKey, iCollectible);
			(dynamic_cast<ICollection*> (buckets[idx]))->add(p);
		}
		if (!keys->member(iKey))
			keys->add(iKey);
	}
}

bool HashedDictionary::member(IKey *iKey) {
	int idx = hash((HashedKey*) iKey);
	bool ret = 0;
	Pair *p;

	if (buckets[idx] != 0) {
		IIterator *it =
				(dynamic_cast<ICollection*> (buckets[idx]))->getIterator();
		while (it->hasCurrent() && !ret) {
			p = (Pair*) it->current();
			it->next();
			if (p->getKey()->equals(iKey))
				ret = 1;
		}
		delete it;
	}
	return ret;
}

ICollectible* HashedDictionary::find(IKey *iKey) {
	int idx = hash((HashedKey*) iKey);
	ICollectible* ret = 0;
	bool find = 0;
	Pair *p;

	if (buckets[idx] != 0) {
		IIterator *it =
				(dynamic_cast<ICollection*> (buckets[idx]))->getIterator();
		while (it->hasCurrent() && !find) {
			p = (Pair*) it->current();
			it->next();
			if (p->getKey()->equals(iKey)) {
				ret = p->getValue();
				find = 1;
			}
		}
		delete it;
	}
	return ret;
}

bool HashedDictionary::isEmpty() {
	return size() == 0;
}

IIterator *HashedDictionary::getIterator() {
	return new DictionaryIterator(keys->getIterator(), this);
}

int HashedDictionary::size() {
	int ret = 0;

	for (int i = 0; i < bckSize; i++) {
		if (buckets[i] != 0) {
			ret += (dynamic_cast<ICollection*> (buckets[i]))->size();
		}
	}
	return ret;
}

bool HashedDictionary::same(ICollectible * dict) {
	return this == dict;
}

string HashedDictionary::toString() {
	stringstream out;
	string sret;

	for (int var = 0; var < bckSize; var++) {
		out << " _________\n";
		if (buckets[var] == 0) {
			out << "|" << var << "  vacio| ";
		} else {
			out << "|" << var << "  ocupado| " << buckets[var]->toString();
		}
		out << "\n ---------\n";
	}
	sret = out.str();
	return sret;
}

HashedDictionary::~HashedDictionary() {
	for (int i = 0; i < bckSize; i++) {
		if (buckets[i] != 0)
			delete buckets[i];
	}
	delete buckets;
	delete keys;
}
